#pragma once
#include <iostream>
#include <fstream>
#include <string>
#include<vector>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <experimental/filesystem>
#include <jsoncpp/json/json.h>
#include"bundle.h"
#include<stdio.h>
namespace cloud
{
    namespace fs=std::experimental::filesystem;
    class FileUtil
    {
    public:
        FileUtil(const std::string filename) : _filename(filename) {}
        size_t FileSize()
        {
           struct stat st1;
           if(stat(_filename.c_str(),&st1)<0)return 0;
           return st1.st_size;
        }
        time_t LastMtime()
        {
            struct stat st;
            if(stat(_filename.c_str(),&st)<0)return -1;
            return st.st_mtim.tv_sec;


        }
        std::string FileName()
        {
           size_t pos= _filename.find_last_of("/");
           if(pos==std::string::npos)
           {
            return _filename;
           }
           return _filename.substr(pos+1);
        }
        time_t LastAtime()
        {
            struct stat st;
            if(stat(_filename.c_str(),&st)<0)return -1;
            return st.st_atim.tv_sec;


        }


        bool GetPosLenth(std::string *res,size_t pos,size_t lenth)
        {
            if((pos+lenth)>FileSize()){
					std::cout << "read open file failed!\n";
					return false;
				}
            std::ifstream fs;
            fs.open(_filename,std::ios::binary);
            if(fs.is_open()==false){
					std::cout << "read open file failed!\n";
					return false;
				}
            fs.seekg(pos,std::ios::beg);
            res->resize(lenth);
            fs.read(&(*res)[0],lenth);//小tips
            if(fs.good()==false){
					std::cout << "read open file failed!\n";
					return false;
				}
            fs.close();
            return true;

        }

        bool GetContent(std::string*res)
        {
           return GetPosLenth(res,0,FileSize());
        }


        bool SetContent(const std::string&content)
        {
            std::ofstream of;
            of.open(_filename,std::ios::binary);
            
            if(of.is_open()==false)
            {
                std::cout<<"setcontent failed";
                return false;
                
            }
            of.write(&content[0],content.size());
            if(of.good()==false)
            {
                std::cout<<"setcontent failed";
                return false;
                
            }
            of.close();
            return true;
        }
        //解压与压缩
         bool Compress(const std::string &packname)
         {
            std::string data;
            if(GetContent(&data)==false)
            {
                std::cout<<"Compress faied";
                return false;
            }

            std::string packed=bundle::pack(bundle::LZIP,data);
            FileUtil fu(packname);
            if(fu.SetContent(packed)==false)
            {
                std::cout<<"Compress faied";
                return false;
            }
            return true;
         }
         bool UnCompress(const std::string &filename)
         {
            std::string data;
            if(GetContent(&data)==false)
            {
                std::cout<<"Compress faied";
                return false;
            }

            std::string packed=bundle::unpack(data);
            FileUtil fu(filename);
            if(fu.SetContent(packed)==false)
            {
                std::cout<<"Compress faied";
                return false;
            }
            return true;
         }
        bool Remove()
        {
            if(Exists())
            {
                int n=remove(_filename.c_str());
                if(n==0)
                  return true;
                else
                  return false;
            }
            return true;
            
        }
        //对目录文件进行操作
        bool Exists()
        {
            return fs::exists(_filename);
        }

        bool CreateDir()
        {
            if(Exists())return true;
            return fs::create_directories(_filename);
        }
        bool ScanDir(std::vector<std::string>*arr)
        {
            CreateDir();
            for(auto &p : fs::directory_iterator(_filename))
            {
                if(fs::is_directory(p))continue;
                arr->push_back(fs::path(p).relative_path().string());
            }
            return true;
        }



    private:
        std::string _filename;
    };
    class JsonFile
    {
        public:
        static bool Serialize(const Json::Value &root,std::string *str)
        {
            Json::StreamWriterBuilder swb;
				std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
				std::stringstream ss; 
				if (sw->write(root, &ss) != 0) {
					std::cout << "json write failed!\n";
					return false;
				}
				*str = ss.str();
                
				return true;
        }
        static bool UnSerialize(const std::string &str, Json::Value *root){
				Json::CharReaderBuilder crb;
				std::unique_ptr<Json::CharReader> cr(crb.newCharReader());
				std::string err;
				bool ret = cr->parse(str.c_str(), str.c_str() + str.size(), root, &err);
				if (ret == false) {
					std::cout << "parse error: " << err << std::endl;
					return false; 
				}
				return true;
			}
    };
}
